import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.laboratory.modules.base.engineeringOrder.domain.EngineeringOrder;
import com.laboratory.modules.base.engineeringOrder.service.EngineeringOrderService;
import com.laboratory.modules.base.engineeringOrder.service.mapper.EngineeringOrderMapper;
import com.laboratory.modules.project.marketingProject.domain.MarketingProject;
import com.laboratory.utils.SecurityUtils;
import com.laboratory.utils.enums.YesNoEnum;
import com.laboratory.utils.enums.finalEnums.TaskStatusCommonEnum;
import lombok.AllArgsConstructor;
import com.laboratory.base.PageInfo;
import com.laboratory.base.QueryHelpMybatisPlus;
import com.laboratory.base.impl.CommonServiceImpl;
import com.laboratory.utils.ConvertUtil;
import com.laboratory.utils.FileUtil;
import com.laboratory.utils.PageUtil;
import com.laboratory.modules.base.engineeringTask.domain.EngineeringTask;
import com.laboratory.modules.base.engineeringTask.service.EngineeringTaskService;
import com.laboratory.modules.base.engineeringTask.service.dto.EngineeringTaskDto;
import com.laboratory.modules.base.engineeringTask.service.dto.EngineeringTaskQueryParam;
import com.laboratory.modules.base.engineeringTask.service.mapper.EngineeringTaskMapper;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.data.domain.Pageable;
import java.util.*;
import java.io.IOException;
import java.util.function.Function;
import java.util.stream.Collectors;
import javax.servlet.http.HttpServletResponse;

@Service
@AllArgsConstructor
// @CacheConfig(cacheNames = EngineeringTaskService.CACHE_KEY)
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true, rollbackFor = Exception.class)
public class EngineeringTaskServiceImpl extends CommonServiceImpl<EngineeringTaskMapper, EngineeringTask> implements EngineeringTaskService {

    // private final RedisUtils redisUtils;
    private final EngineeringTaskMapper engineeringTaskMapper;

    private final EngineeringOrderMapper orderMapper;

    /* -----------start-------分页示例 详情表和主表回显 查询 组合策略优化  ---- start--------------------*/
    @Override
    public PageInfo<EngineeringTaskDto> queryAllByDeptId(EngineeringTaskQueryParam query, Pageable pageable) {
        if (!SecurityUtils.currentUserIsAdmin()) {
            // 获取当前登录人是不是 市场部领导 根据角色编码 市场运营领导（bYzlpxyS8R）：来决定,如果有其他角色可以进行拓展
            if (SecurityUtils.getCurrentUserRole().isEmpty()) {
                log.error("当前登录人没有任何角色集合：" + SecurityUtils.getCurrentUser().getUsername());
                return new PageInfo<>();
            }
            boolean isManager = SecurityUtils.getCurrentUserRole().stream().anyMatch(k -> "bYzlpxyS8R".equals(k.getCodeStr()));
            if(!isManager){
                // 不是领导只能看自己部门的
                query.setDeptId(SecurityUtils.getCurrentUserDeptId());
            }
        }
        QueryWrapper<EngineeringTask> predicate = QueryHelpMybatisPlus.getPredicate(query);

        Integer strategy = optimizeQueryWithStrategy(query, predicate);
        if(strategy == 0){
            return new PageInfo<>();
        }

        IPage<EngineeringTask> queryPage = PageUtil.toMybatisPage(pageable);
        IPage<EngineeringTask> page = engineeringTaskMapper.selectPage(queryPage, predicate);
        PageInfo<EngineeringTaskDto> engineeringTaskDtoPageInfo = ConvertUtil.convertPage(page, EngineeringTaskDto.class);
        if(!engineeringTaskDtoPageInfo.getContent().isEmpty()){
            // 拼接主表 工程单 信息
            Set<Long> orderIds = engineeringTaskDtoPageInfo.getContent().stream().map(EngineeringTaskDto::getOrderId).collect(Collectors.toSet());
            List<EngineeringOrder> engineeringOrders = orderMapper.selectBatchIds(orderIds);
            Map<Long, EngineeringOrder> orderMap = engineeringOrders.stream()
                    .filter(Objects::nonNull) // 过滤 null 对象
                    .filter(s -> s.getId() != null) // 过滤 ID 为 null 的对象
                    .collect(Collectors.toMap(
                            EngineeringOrder::getId,
                            Function.identity(),
                            (existing, replacement) -> existing,
                            () -> new HashMap<>((int) (engineeringOrders.size() / 0.75f) + 1)
                    ));
            engineeringTaskDtoPageInfo.getContent().forEach(engineeringOrder -> {
                EngineeringOrder order = orderMap.get(engineeringOrder.getOrderId());
                if(order != null){
                    engineeringOrder.setOrderName(order.getProjectName());
                    engineeringOrder.setContractNo(order.getContractNo());
                }
            });

        }
        return engineeringTaskDtoPageInfo;
    }

    // 使用策略模式优化
    public Integer optimizeQueryWithStrategy(EngineeringTaskQueryParam query,QueryWrapper<EngineeringTask> predicate) {

        int result = 0;
        // 策略模式：根据查询条件决定处理方式
        if (shouldQueryOrders(query)) {
            Set<Long> orderIds = queryOrderIds(query);
            if (!orderIds.isEmpty()) {
                predicate.in("order_id", orderIds);
                result = orderIds.size();
            }
        } else {
            predicate.isNotNull("order_id");
            result = 1;
        }
        return result;
    }

    private boolean shouldQueryOrders(EngineeringTaskQueryParam query) {
        return Objects.nonNull(query.getContractNo()) || query.getOrderName() != null;
    }

    private Set<Long> queryOrderIds(EngineeringTaskQueryParam query) {
        String orderName = Optional.ofNullable(query.getOrderName())
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .orElse(null);

        String contractNo = Optional.ofNullable(query.getContractNo())
                .map(String::trim)
                .filter(s -> !s.isEmpty())
                .orElse(null);

        if (orderName == null && contractNo == null) {
            return Collections.emptySet();
        }

        LambdaQueryWrapper<EngineeringOrder> orderQueryWrapper = new LambdaQueryWrapper<>();

        Optional.ofNullable(orderName)
                .ifPresent(name -> orderQueryWrapper.like(EngineeringOrder::getProjectName, name));

        Optional.ofNullable(contractNo)
                .ifPresent(no -> orderQueryWrapper.like(EngineeringOrder::getContractNo, no));

        orderQueryWrapper.eq(EngineeringOrder::getDelStatus, YesNoEnum.FALSE.getValue());

        List<EngineeringOrder> orders = orderMapper.selectList(orderQueryWrapper);

        return orders.stream()
                .map(EngineeringOrder::getId)
                .collect(Collectors.toSet());
    }

    /* -----------end-------分页示例 详情表和主表回显 查询 组合策略优化  ----end--------------------*/

    /* todo 新增专门的关联任务接口 避免接口操作越权 */

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int handleTaskComplete(EngineeringTaskDto resources){

        // 更新工程单状态
        EngineeringTask byId = getById(resources.getId());
        EngineeringOrder order = orderMapper.selectById(resources.getOrderId());
        if (null != byId && null != order) {

            // 获取所有兄弟 子任务状态
            List<EngineeringTask> list = engineeringTaskMapper.selectList(new QueryWrapper<EngineeringTask>()
                    .eq("order_id", byId.getOrderId()));
            if (!list.isEmpty()) {
                // 尝试找到集合没有完成的任务(排除他自己)
                boolean b = list.stream().anyMatch(item -> !item.getStatus().equals(TaskStatusCommonEnum.HAS_FINISH.getStringValue()) && !Objects.equals(item.getId(), byId.getId()));
                if (!b) {
                    // 一个都没有 则更新父亲：工程单状态为已完成
                    orderMapper.lambdaUpdate().eq(EngineeringOrder::getId, byId.getOrderId())
                            .set(EngineeringOrder::getStatus, TaskStatusCommonEnum.HAS_FINISH.getStringValue()).update();
                }
            }
            // 最后更新自己
            update(new LambdaUpdateWrapper<EngineeringTask>().eq(EngineeringTask::getId, resources.getId()).set(EngineeringTask::getStatus, TaskStatusCommonEnum.HAS_FINISH.getStringValue()));

            return 1;
        }
        log.error("**************** 工程单对象：" + order);
        log.error("**************** 工程单任务对象：" + byId);
        return 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int removeByIds(Set<Long> ids){
        // delCaches(ids);
        // return engineeringTaskMapper.deleteBatchIds(ids);
        if(ids.isEmpty()){
            return 0;
        }
        LambdaUpdateWrapper<EngineeringTask> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.in(EngineeringTask::getId, ids);
        updateWrapper.set(EngineeringTask::getDelStatus, YesNoEnum.TRUE.getValue());
        updateWrapper.set(EngineeringTask::getUpdateBy, SecurityUtils.getCurrentUsername());
        updateWrapper.set(EngineeringTask::getUpdateTime, new Date());
        update(updateWrapper);
        return ids.size();
    }

    @Override
    public void download(List<EngineeringTaskDto> all, HttpServletResponse response) throws IOException {
        List<Map<String, Object>> list = new ArrayList<>();
        for (EngineeringTaskDto engineeringTask : all) {
            Map<String,Object> map = new LinkedHashMap<>();
            map.put("交付物", engineeringTask.getDeliverable());
            map.put("交付内容", engineeringTask.getDeliveryContent());
            map.put("数量", engineeringTask.getQuantity());
            map.put("交付方式", engineeringTask.getDeliveryMethod());
            map.put("创建人", engineeringTask.getCreateBy());
            map.put("创建时间", engineeringTask.getCreateTime());
            map.put("修改人", engineeringTask.getUpdateBy());
            map.put("修改时间", engineeringTask.getUpdateTime());
            map.put("删除状态", engineeringTask.getDelStatus());
            map.put("工程单ID", engineeringTask.getOrderId());
            map.put("执行部门名称", engineeringTask.getDeptName());
            map.put("交付标准", engineeringTask.getDeliveryStandard());
            map.put("执行部门", engineeringTask.getDeptId());
            map.put("交付日期", engineeringTask.getDeliveryDate());
            map.put("备注", engineeringTask.getRemark());
            list.add(map);
        }
        FileUtil.downloadExcel(list, response);
    }


}
